﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using BizAppFactory.Domain;
using Microsoft.VisualStudio.Modeling;

namespace BizAppFactory.DomainModel.CustomEditors.MethodEditor
{
    public partial class MethodForm : Form
    {
        Method editedMethod;

        public Method EditedMethod
        {
            get { return editedMethod; }
            set { editedMethod = value; }
        }

        Transaction transaction;

        public MethodForm()
        {
            InitializeComponent();
            parametersDataGridView.AutoGenerateColumns = false;
        }

        private void MethodForm_Load(object sender, EventArgs e)
        {
            DataBindToControl(EditedMethod);

            Store store = EditorHelper.GetStore(EditedMethod);
            transaction = store.TransactionManager.BeginTransaction("BindMethodData");
        }

        private void okButton_Click(object sender, EventArgs e)
        {
            DataBindToDomainObject(transaction.Store, EditedMethod);
            transaction.Commit();
            Close();
        }

        private void cancelButton_Click(object sender, EventArgs e)
        {
            transaction.Rollback();
            Close();
        }

 
        private void DataBindToControl(Method method)
        {
            BindComboBoxItems();
            BindParameterDataGridView();
            //Bind Method
            methodNameTextBox.Text = method.Name;
            accessModifierComboBox.Text = method.AccessModifier.ToString();
            isStaticCheckBox.Checked = method.IsStatic;
            
            //Bind Method access modifier combo values
            accessModifierComboBox.Items.AddRange(Enum.GetNames(typeof(MethodAccessModifier)));

            //Bind Return Type
            if (EditedMethod.ReturnType != null)
            {
                if (method.ReturnType.BasicDataType != BasicDataTypes.Null)
                {
                    returnBasicTypeComboBox.Text = method.ReturnType.BasicDataType.ToString();
                }
                else
                {
                    returnBasicTypeComboBox.Text = null;
                }
                
                returnIsListCheckBox.Checked = method.ReturnType.IsList;
                
                if (method.ReturnType.DomainClass != null)
                {
                    returnDomainDataTypeComboBox.SelectedValue = method.ReturnType.DomainClass.Id;
                }
            }
        }

        private void BindParameterDataGridView()
        {
           BindingList<MethodParameter> paramBindingList = new BindingList<MethodParameter>();
            foreach(MethodParameter param in EditedMethod.MethodParameters)
            {
                paramBindingList.Add(param);
            }

            parametersDataGridView.DataSource = paramBindingList;
        }

        private void BindComboBoxItems()
        {
            #region Return Type combos
            // Bind Return Type, Basic Data Type combo values
            returnBasicTypeComboBox.Items.Add("");
            returnBasicTypeComboBox.Items.AddRange(Enum.GetNames(typeof(BasicDataTypes)));

            // Bind Return Type, Domain Data Type combo values
            List<ComboGiudDto> dataTypeComboGuidDtos = new List<ComboGiudDto>();

            // add the null object
            dataTypeComboGuidDtos.Add(new ComboGiudDto());

            foreach (DomainClass domainClass in EditorHelper.GetModel(EditedMethod).DomainClasses)
            {
                dataTypeComboGuidDtos.Add(new ComboGiudDto(domainClass.Id, domainClass.Name));
            }

            returnDomainDataTypeComboBox.DataSource = dataTypeComboGuidDtos;
            returnDomainDataTypeComboBox.DisplayMember = "DisplayName";
            returnDomainDataTypeComboBox.ValueMember = "Id";
            #endregion

            #region Parameter combos
            // Bind Parameter Type, Basic Data Type combo values
            paramBasicTypeComboBox.Items.Add("");
            paramBasicTypeComboBox.Items.AddRange(Enum.GetNames(typeof(BasicDataTypes)));

            // Bind Parameter Type, Domain Data Type combo values
            List<ComboGiudDto> paramDataTypeComboGuidDtos = new List<ComboGiudDto>();

            // add the null object
            paramDataTypeComboGuidDtos.Add(new ComboGiudDto());

            foreach (DomainClass domainClass in EditorHelper.GetModel(EditedMethod).DomainClasses)
            {
                paramDataTypeComboGuidDtos.Add(new ComboGiudDto(domainClass.Id, domainClass.Name));
            }

            paramDomainDataTypeComboBox.DataSource = paramDataTypeComboGuidDtos;
            paramDomainDataTypeComboBox.DisplayMember = "DisplayName";
            paramDomainDataTypeComboBox.ValueMember = "Id";          
            #endregion
        }
        
        private void DataBindToDomainObject(Store store, Method method)
        {
            method.Name = methodNameTextBox.Text;
            method.AccessModifier = (MethodAccessModifier)Enum.Parse(typeof(MethodAccessModifier), accessModifierComboBox.Text);
            method.IsStatic = isStaticCheckBox.Checked;

            if (EditedMethod.ReturnType == null)
            {
                EditedMethod.ReturnType = new MethodType(store);
            }

            // Bind Return Basic Data Type
            method.ReturnType.BasicDataType = ParseBasicDataType(returnBasicTypeComboBox.Text);           

            // Bind Return Domain Type
            ComboGiudDto selectedComboDto = (ComboGiudDto)returnDomainDataTypeComboBox.SelectedItem;
            method.ReturnType.DomainClass = ParseDomainClassFromComo(selectedComboDto);

            // Bind Return IsList
            method.ReturnType.IsList = returnIsListCheckBox.Checked;

        }

        MethodParameter _selectedMethodParameter = null;
        
        private void paramSaveButton_Click(object sender, EventArgs e)
        {
            MethodParameter methodParameter;

            if (_selectedMethodParameter == null)
            {
                methodParameter = new MethodParameter(transaction.Store);
                EditedMethod.MethodParameters.Add(methodParameter);
            }
            else
            {
                methodParameter = _selectedMethodParameter;
            }
            methodParameter.Name = paramNameTextBox.Text;

            // Bind Return Basic Data Type
            methodParameter.BasicDataType = ParseBasicDataType(paramBasicTypeComboBox.Text);

            // Bind Return Domain Type
            ComboGiudDto selectedComboDto = (ComboGiudDto)paramDomainDataTypeComboBox.SelectedItem;
            methodParameter.DomainClass = ParseDomainClassFromComo(selectedComboDto);

            // Bind Return IsList
            methodParameter.IsList = paramIsListCheckBox.Checked;

            if (_selectedMethodParameter == null)
            {
                ((BindingList<MethodParameter>)parametersDataGridView.DataSource).Add(methodParameter);

                // select the saved param when new is saved
                foreach (DataGridViewRow row in parametersDataGridView.Rows)
                {
                    if ((Guid)row.Cells["Id"].Value == methodParameter.Id)
                    {
                        row.Selected = true;
                        _selectedMethodParameter = methodParameter;
                    }
                }
            }

        }

        #region Data type bindings
        DomainClass ParseDomainClassFromComo(ComboGiudDto comboGuidDto)
        {
            BizAppDomainModel model = EditorHelper.GetModel(editedMethod);

            DomainClass domainClass;

            if (comboGuidDto != null && !comboGuidDto.IsNullObject)
            {
                Guid selectedDomainDataTypeGuid = comboGuidDto.Id;

                domainClass = (from d in model.DomainClasses
                                                 where
                                                     d.Id == selectedDomainDataTypeGuid
                                                 select
                                                     d).Single<DomainClass>();
            }
            else
            {
                domainClass = null;
            }

            return domainClass;
        }

        BasicDataTypes ParseBasicDataType(string typeName)
        {
            BasicDataTypes basicDataType;

            // Bind Return Basic Data Type
            if (!String.IsNullOrEmpty(typeName))
            {
                basicDataType = (BasicDataTypes)Enum.Parse(typeof(BasicDataTypes), typeName);
            }
            else
            {
                basicDataType = BasicDataTypes.Null;
            }

            return basicDataType;
        }
        #endregion

        private void parametersDataGridView_SelectionChanged(object sender, EventArgs e)
        {
            if (parametersDataGridView.SelectedRows.Count > 0)
            {
                Guid id = (Guid)parametersDataGridView.SelectedRows[0].Cells["Id"].Value;
                BizAppDomainModel model = EditorHelper.GetModel(EditedMethod);
                _selectedMethodParameter = (from p in EditedMethod.MethodParameters
                                            where
                                             p.Id == id
                                            select p).Single<MethodParameter>();

                BindToParameterControls(_selectedMethodParameter);
            }
            else
            {
                CleanParamControls();
            }
        }

        void CleanParamControls()
        {
            paramNameTextBox.Text = "";
            paramIsListCheckBox.Checked = false;
            paramBasicTypeComboBox.Text = "";
            paramDomainDataTypeComboBox.SelectedValue = "";
            _selectedMethodParameter = null;

        }

        void BindToParameterControls(MethodParameter param)
        {
            paramNameTextBox.Text = param.Name;
            paramIsListCheckBox.Checked = param.IsList;

            if (param.BasicDataType != BasicDataTypes.Null)
            {
                paramBasicTypeComboBox.Text = param.BasicDataType.ToString();
            }
            else
            {
                paramBasicTypeComboBox.Text = "";
            }

            if (param.DomainClass != null)
            {
                paramDomainDataTypeComboBox.SelectedValue = param.DomainClass.Id;
            }

        }

        private void paramNewButton_Click(object sender, EventArgs e)
        {
            CleanParamControls();
        }

        private void paramDeleteButton_Click(object sender, EventArgs e)
        {
            if (_selectedMethodParameter != null)
            {
                foreach(DataGridViewRow row in parametersDataGridView.SelectedRows)
                {
                    Guid id = (Guid)row.Cells["Id"].Value;
                    BizAppDomainModel model = EditorHelper.GetModel(EditedMethod);

                    MethodParameter deletedMethodParameter = (from p in EditedMethod.MethodParameters
                                                where
                                                 p.Id == id
                                                select p).Single<MethodParameter>();

                    ((BindingList<MethodParameter>)parametersDataGridView.DataSource).Remove(deletedMethodParameter);
                    EditedMethod.MethodParameters.Remove(deletedMethodParameter);
                }
            }
        }
    }
}
